// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <nebula/bits/bitmap_builders.h>

#include <cstdint>
#include <cstring>
#include <memory>
#include <type_traits>
#include <utility>

#include <nebula/core/buffer.h>

#include <turbo/utility/status.h>
#include <nebula/bits/bit_util.h>

namespace nebula::internal {

    namespace {

        void FillBitsFromBytes(const std::vector<uint8_t> &bytes, uint8_t *bits) {
            for (size_t i = 0; i < bytes.size(); ++i) {
                if (bytes[i] > 0) {
                    bit_util::SetBit(bits, i);
                }
            }
        }

    }  // namespace

    turbo::Result<std::shared_ptr<Buffer>> BytesToBits(const std::vector<uint8_t> &bytes,
                                                       MemoryPool *pool) {
        int64_t bit_length = bit_util::BytesForBits(bytes.size());

        TURBO_MOVE_OR_RAISE(auto buffer, allocate_buffer(bit_length, pool));
        uint8_t *out_buf = buffer->mutable_data();
        memset(out_buf, 0, static_cast<size_t>(buffer->capacity()));
        FillBitsFromBytes(bytes, out_buf);
        // R build with openSUSE155 requires an explicit shared_ptr construction
        return std::shared_ptr<Buffer>(std::move(buffer));
    }

    turbo::Result<std::shared_ptr<Buffer>> BitmapAllButOne(MemoryPool *pool, int64_t length,
                                                           int64_t straggler_pos, bool value) {
        if (straggler_pos < 0 || straggler_pos >= length) {
            return turbo::invalid_argument_error("invalid straggler_pos ", straggler_pos);
        }

        TURBO_MOVE_OR_RAISE(auto buffer,
                            allocate_buffer(bit_util::BytesForBits(length), pool));

        auto bitmap_data = buffer->mutable_data();
        bit_util::SetBitsTo(bitmap_data, 0, length, value);
        bit_util::SetBitTo(bitmap_data, straggler_pos, !value);
        // R build with openSUSE155 requires an explicit shared_ptr construction
        return std::shared_ptr<Buffer>(std::move(buffer));
    }

}  // namespace nebula::internal
